﻿#region Librerias

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ESF.Twain;
using ESF.Twain.TwainNative;
using System.Drawing.Imaging;
using ESF.General.Entity;
using ESF.ImageProcessing;
using ESF.General;
using ESF.General.Text;
using ThoughtWorks.QRCode.Codec.Reader;
using ThoughtWorks.QRCode.Codec;
using ThoughtWorks.QRCode.Codec.Data;

#endregion


namespace ESF.WinForms.Controls.ScannerControls
{
	public partial class uscScanWork : UserControl
	{
		#region Eventos y Delegados

		public event GetList GetClientList;
		
		#endregion


		#region Miembros

		//private AreaSettings _AreaSettings;

		private ESF.Twain.Twain _Twain;
        
		private ScanSettings _ScanSettings;

		private BasicReference _CurrentDeviceRefTested;

		private QRCodeDecoder _QRDecoder;

		#endregion


		#region Constructor
		
		public uscScanWork()
		{
			InitializeComponent();
			
			_QRDecoder = new QRCodeDecoder ();
		}

		#endregion
		
		
		#region Funciones
		
		private void ClearScanParameters ()
		{
			if (!ListLoader.IsThereSelectionBasicReference (ddlScanDevice))
			{
				if (!ListLoader.SelectByNameBasicReference (ddlScanDevice, "sipc", ComparisonTypes.LikeFull))
				{
					ListLoader.SelectByNameBasicReference (ddlScanDevice, "vrs", ComparisonTypes.LikeFull);
				}
			}

			DefineScanSettings ();

			EnableScan ();
		}


		private bool LoadScanners ()
		{
			ClearScanParameters ();

			if (!ListLoader.LoadListTexts (ddlScanDevice, _Twain.SourceNames))
			{
				WinFormsHelper.ShowError (this, "No hay scanners disponibles, conecte uno e intente de nuevo");
				Hide ();
							
				return false;
			}

			ListLoader.RemoveSelectItem (ddlScanDevice);
			
			ddlScanDevice.SelectedIndex = 0;
			
			return true;
		}


		private void LoadControl ()
		{	
			_Twain = new ESF.Twain.Twain (new WinFormsWindowMessageHook (this));

			_Twain.TransferImage += _Twain_TransferImage;

            _Twain.ScanningComplete += delegate
            {
                EnableScan ();
            };
			

			if (!LoadScanners ())
			{
				return;
			}

			ListLoader.LoadList (ddlScanColor,
				"Blanco y Negro", "BlackAndWhite", 
				"Escala de Grises", "GreyScale",
				"Color", "Color");

			ListLoader.LoadList (ddlScanBarCodeArea,
				"Completo", "Full",
				"Mitad de Arriba", "Top",
				"Mitad de Abajo", "Bottom",
				"Mitad Arriba Derecha", "TopRight",
				"Mitad Arriba Izquierda", "TopLeft",
				"Mitad Abajo Derecha", "BottomRight",
				"Mitad Abajo Izquierda", "BottomLeft");

			ListLoader.LoadList (ddlScanBarCodeDirection,
				"Ambos", "Both",
				"Horizontal", "Horizontal",
				"Vertical", "Vertical");

			ListLoader.LoadList (ddlScanImageFormat, 
				"Bitmap (BMP)", ImageFormat.Bmp.ToString (),
				"Graphics Interchange Format (GIF)", ImageFormat.Gif.ToString (),
				"Joint Photographic Experts Group (JPEG)", ImageFormat.Jpeg.ToString (),
				"Portable Network Graphics (PNG)", ImageFormat.Png.ToString (),
				"Tag Image File Format (TIFF)", ImageFormat.Tiff.ToString ());

			ListLoader.LoadList (ddlScanResolution, "200 x 200", "200", "300 x 300", "300", "600 x 600", "600");
			
			// TODO: Cargar las empresas desde la DB
			

			ListLoader.LoadList (ddlScanEnterprise, GetClientList ());

			ListLoader.LoadList (ddlScanBarCodeType, typeof (BarcodeType));

			ListLoader.Clear (ddlScanEnterpriseDocumentType);

			
			ClearScanParameters ();
		}

		#endregion


		#region Eventos de Twain

		protected void _Twain_TransferImage (Object sender, TransferImageEventArgs args)
        {
			// TODO: Carpeta de Empresa / Tipo Documento / Lote / Paquete / Grupos x Codigo de Barras o manual

			string TMPStoreFolder;
			string TMPImageFilename;

			List<string> lstBarCodes;

			SliceSection barCodeSlice;

			ScanDirection barCodeScanDirection;

			Bitmap sliceBarcodeImage;

			
			BarcodeHelper.FullScanBarcodeTypes = (BarcodeType) Enum.Parse (typeof (BarcodeType), ListLoader.GetSelectedValueBasicReference (ddlScanBarCodeType).Code);
			
			barCodeSlice = (SliceSection) Enum.Parse (typeof (SliceSection), ListLoader.GetSelectedValueBasicReference (ddlScanBarCodeArea).Code);

			barCodeScanDirection = (ScanDirection) Enum.Parse (typeof (ScanDirection), ListLoader.GetSelectedValueBasicReference (ddlScanBarCodeDirection).Code);

			sliceBarcodeImage = (Bitmap) ImageHelper.Crop (args.Image, barCodeSlice);

			lstBarCodes = new List<string> ();

			if (BarcodeHelper.FullScanBarcodeTypes == BarcodeType.QR)
			{	
				lstBarCodes.Add (_QRDecoder.decode (new QRCodeBitmapImage (sliceBarcodeImage)));				
			}
			else
			{
				lstBarCodes = BarcodeHelper.FullScanPage (sliceBarcodeImage, barCodeScanDirection, 100);
			}

			if (lstBarCodes.Count > 0)
			{
				WinFormsHelper.ShowOK (this, "Códigos de Barra Detectados:\n\n" + TextHelper.ToString (", ", lstBarCodes));

				string b = lstBarCodes.Find (bc => bc.StartsWith ("p"));

				if (!string.IsNullOrEmpty (b))
				{
					uscImageSheetGroupSet.AddSet (b);
				}
				else
				{
					uscImageSheetGroupSet.AddSet (lstBarCodes [0]);
				}
			}

			TMPStoreFolder = @"c:\Temp\Scan\" + ListLoader.GetSelectedValue <BasicReference> (ddlScanEnterprise).Code 
				+ @"\" + ListLoader.GetSelectedValue <BasicReference> (ddlScanEnterpriseDocumentType).Code;
				  
			FileHelper.EnsureFolder (TMPStoreFolder);

			TMPImageFilename = TMPStoreFolder + Guid.NewGuid ().ToString () + ".jpg";

			args.Image.Save (TMPImageFilename, ImageFormat.Jpeg);

			uscImageSheetGroupSet.AddImage (TMPImageFilename);
			uscImageSheetGroupSet.Refresh ();
		}


		private void EnableScan ()
		{
			btnScanStart.Enabled = 
				ListLoader.IsThereSelectionBasicReference (ddlScanDevice) && 
				ListLoader.IsThereSelectionBasicReference (ddlScanEnterpriseDocumentType);
		}

		
		private void DefineScanSettings ()
		{
			IList<Capabilities> caps;

			BasicReference deviceRef;
			

			deviceRef = ListLoader.GetSelectedValueBasicReference (ddlScanDevice);

			// No esta definido o ya fue revisado
			if (deviceRef == null || (_CurrentDeviceRefTested != null && _CurrentDeviceRefTested.Equals (deviceRef)))
			{
				return;
			}

			_CurrentDeviceRefTested = deviceRef;

			try
			{
				_Twain.SelectSource (deviceRef.Code);
			
				#region Capacidades

				caps = _Twain.Diagnostics (new WinFormsWindowMessageHook (this), deviceRef.Code);

				ListLoader.AddItem (ddlScanPaperSource, "Bed", "Cama");

				if (caps.Contains (Capabilities.FeederEnabled))
				{
					ListLoader.AddItem (ddlScanPaperSource, Capabilities.FeederEnabled.ToString (), "Bandeja (Una cara)");

					if (caps.Contains (Capabilities.DuplexEnabled))
					{
						ListLoader.AddItem (ddlScanPaperSource, Capabilities.DuplexEnabled.ToString (), "Bandeja (Dos caras)");
					}
				}

				#endregion

				Refresh ();
			}
			catch (Exception pEx)
			{
				ListLoader.AddItem (ddlScanPaperSource, "Bed", "Cama *");
				Log.Error (pEx);
			}

			ddlScanPaperSource.SelectedIndex = 0;
		}

		#endregion


		#region Eventos de los Botones

		private void btnScanDefineDocumentParams_Click(object sender, EventArgs e)
		{
			DefineScanSettings ();
		}


		private void btnScanStart_Click(object sender, EventArgs e)
		{
			try
            {
				_ScanSettings = new ScanSettings
				{
					UseDocumentFeeder = (ListLoader.IsSelectedValueINBasicReference (ddlScanPaperSource, "FeederEnabled", "DuplexEnabled")),
					ShowTwainUI = false,
					ShowProgressIndicatorUI = false,
					UseDuplex = (ListLoader.IsSelectedValueINBasicReference (ddlScanPaperSource, "DuplexEnabled")),
					Page = new PageSettings ()
					{
						Orientation = Twain.TwainNative.Orientation.Auto
						//Size = PageType.
					},
					//AbortWhenNoPaperDetectable = true,
					//UseAutoScanCache = true,
					Resolution = new ResolutionSettings () { 
						ColourSetting = (ColourSetting) Enum.Parse (typeof (ColourSetting), ListLoader.GetSelectedValue <BasicReference> (ddlScanColor).Code),
						Dpi = int.Parse (ListLoader.GetSelectedValue <BasicReference> (ddlScanResolution).Code) },
					//Area = !chkScanUseGrabArea.Checked ? null : _AreaSettings,
					Rotation = new RotationSettings
					{
						AutomaticRotate = true,
						AutomaticBorderDetection = true
					}
				};
				
				_Twain.StartScanning (_ScanSettings);
            }
            catch (Exception pEx)
            {
                WinFormsHelper.ShowError (this, pEx);
                EnableScan ();
            }
		}

		#endregion


		#region Eventos de las Listas

		private void ddlScanEnterprise_SelectedIndexChanged(object sender, EventArgs e)
		{
			BasicReference enterprise;
			
			
			enterprise =  ListLoader.GetSelectedValueBasicReference (ddlScanEnterprise);

			if (enterprise == null) 
			{
				ListLoader.Clear (ddlScanEnterpriseDocumentType);

				ClearScanParameters ();

				return;
			}

			ListLoader.LoadList (ddlScanEnterpriseDocumentType, 
				GetClientList ().Find (en => en.Code == enterprise.Code).ExtraValues ["DocumentTypes"] as List<BasicReference>);
		}


		private void ddlScanEnterpriseDocumentType_SelectedIndexChanged(object sender, EventArgs e)
		{
			ClearScanParameters ();
			
			if (ListLoader.IsThereSelectionBasicReference (ddlScanEnterpriseDocumentType))
			{
				// TODO: Poner valores reales, derivados del sistema
				#region Demo

				ListLoader.SelectByNameBasicReference (ddlScanBarCodeType, "All");

				ListLoader.SelectByCodeBasicReference (ddlScanColor, "GreyScale");

				ListLoader.SelectByCodeBasicReference (ddlScanResolution, "300");

				ListLoader.SelectByCodeBasicReference (ddlScanBarCodeDirection, "Both");

				ListLoader.SelectByCodeBasicReference (ddlScanBarCodeArea, "Bottom");

				ListLoader.SelectByCodeBasicReference (ddlScanImageFormat, "Jpeg");

				#endregion
			}
		}


		private void ddlScanDevice_SelectedIndexChanged(object sender, EventArgs e)
		{
			ClearScanParameters ();
		}

		#endregion


		#region Eventos de Carga

		private void uscScanWork_Load(object sender, EventArgs e)
		{
			LoadControl ();
		}

		#endregion
	}
}
